#include "wheelTimer.h"

// 哈希函数
static int hash(int netfd) { return netfd % HASH_TABLE_SIZE; }

// 初始化哈希表
static void hash_table_init(hash_table_t *ht) {
  for (int i = 0; i < HASH_TABLE_SIZE; i++) {
    ht->table[i] = NULL;
  }
}

// 哈希表中加入新的元素
static void hash_table_put(hash_table_t *ht, int netfd, int slot) {
  int h = hash(netfd);
  hash_node_t *new_node = (hash_node_t *)malloc(sizeof(hash_node_t));
  new_node->netfd = netfd;
  new_node->slot = slot;
  new_node->next = ht->table[h];
  ht->table[h] = new_node;
}

// 根据 key 查询 value
static int hash_table_get(hash_table_t *ht, int netfd) {
  int h = hash(netfd);
  hash_node_t *curr = ht->table[h];
  while (curr != NULL) {
    if (curr->netfd == netfd) {
      return curr->slot;
    }
    curr = curr->next;
  }
  return -1; // 未找到
}

// 从哈希表中移除元素
static void hash_table_remove(hash_table_t *ht, int netfd) {
  int h = hash(netfd);
  hash_node_t *prev = NULL;
  hash_node_t *curr = ht->table[h];
  while (curr != NULL) {
    if (curr->netfd == netfd) {
      if (prev == NULL) {
        ht->table[h] = curr->next;
      } else {
        prev->next = curr->next;
      }
      free(curr);
      break;
    }
    prev = curr;
    curr = curr->next;
  }
}

// 销毁哈希表
static void hash_table_destroy(hash_table_t *ht) {
  for (int i = 0; i < HASH_TABLE_SIZE; i++) {
    hash_node_t *curr = ht->table[i];
    while (curr != NULL) {
      hash_node_t *next = curr->next;
      free(curr);
      curr = next;
    }
  }
}

// 初始化时间轮盘
time_wheel_t *init_wheel() {
  printf("==init_wheel==\n");
  time_wheel_t *tw = (time_wheel_t *)malloc(sizeof(time_wheel_t));
  if (tw == NULL) {
    perror("Failed to allocate memory for time wheel");
    return NULL;
  }

  for (int i = 0; i < QUEUE_SIZE; i++) {
    tw->wheel[i] = NULL;
  }
  hash_table_init(&tw->hash_table); // 初始化哈希表
  tw->current_slot = 0;

  return tw;
}

// 新连接加入时间轮盘
void new_connect(time_wheel_t *tw, client_info_t *client) {
  printf("++new_connect++\n");
  int netfd = client->client_conn_info.netfd;

  // 添加到当前槽位
  client->lastTime = time(NULL); // 更新最后活跃时间
  client->next = tw->wheel[tw->current_slot];
  tw->wheel[tw->current_slot] = client;

  // 添加到哈希表
  hash_table_put(&tw->hash_table, netfd, tw->current_slot);
}

// 用户发言，更新客户端活跃时间
void update_client(time_wheel_t *tw, int netfd) {
  printf("**++update_client++**\n");
  int slot = hash_table_get(&tw->hash_table, netfd);
  if (slot == -1) {
    return; // 未找到客户端
  }
  // 从原槽位中移除
  client_info_t *prev = NULL;
  client_info_t *curr = tw->wheel[slot];
  while (curr != NULL) {
    if (curr->client_conn_info.netfd == netfd) {
      if (prev == NULL) {
        tw->wheel[slot] = curr->next;
      } else {
        prev->next = curr->next;
      }
      break;
    }
    prev = curr;
    curr = curr->next;
  }

  // 添加到当前槽位的前一个槽位
  int new_slot = (tw->current_slot - 1 + QUEUE_SIZE) % QUEUE_SIZE;
  curr->lastTime = time(NULL); // 更新最后活跃时间
  curr->next = tw->wheel[new_slot];
  tw->wheel[new_slot] = curr;

  // 更新哈希表
  hash_table_remove(&tw->hash_table, netfd);
  hash_table_put(&tw->hash_table, netfd, new_slot);
}

// 客户端主动断开连接，更新时间轮盘
void remove_client(time_wheel_t *tw, int netfd) {
  printf("--remove_client--\n");
  int slot = hash_table_get(&tw->hash_table, netfd);
  if (slot == -1) {
    return; // 未找到客户端
  }

  // 从时间轮盘中移除
  client_info_t *prev = NULL;
  client_info_t *curr = tw->wheel[slot];
  while (curr != NULL) {
    if (curr->client_conn_info.netfd == netfd) {
      if (prev == NULL) {
        tw->wheel[slot] = curr->next;
      } else {
        prev->next = curr->next;
      }
      free(curr);
      break;
    }
    prev = curr;
    curr = curr->next;
  }

  // 从哈希表中移除
  hash_table_remove(&tw->hash_table, netfd);
}

// 检查并关闭超时的客户端
void check_timeout(time_wheel_t *tw, int epfd, conn_info *client, int *index) {
  time_t now = time(NULL);
  printf("##check_timeout##,%s", ctime(&now));
  int slot_to_check = tw->current_slot; // 检查当前槽位
  client_info_t *curr = tw->wheel[slot_to_check];
  while (curr != NULL) {
    LOG_CLIENT_EVENT(LOG_WARNING, curr->client_conn_info,
                     "Connection timeout (Last active: %ld seconds ago)",
                     now - curr->lastTime);

    printf("$$$$$$$Closing client fd: %d (timeout)\n",
           curr->client_conn_info.netfd);
    /* epoll_ctl(epfd, EPOLL_CTL_DEL, curr->client_conn_info.netfd, NULL);// 从
     * epoll 中移除 */
    /* close(curr->client_conn_info.netfd); // 关闭客户端描述符 */
    printf("**\n");

    // 更新 client 数组的状态
    int k = index[curr->client_conn_info.netfd];
    /* printf("k=%d\tnetfd=%d\tis_alive=%d\tis_login=%d\n",k,client[k].netfd,client[k].is_alive,client[k].is_login);
     */
    printf("k=%d\tnetfd=%d\tis_alive=%d\n", k, client[k].netfd,
           client[k].is_alive);
    epoll_del(epfd, curr->client_conn_info.netfd);
    client[k].is_alive = 0;
    client[k].netfd = 0;
    /* client[k].is_login = 0; */
    index[k] = -1;
    close(curr->client_conn_info.netfd);
    printf("k=%d\tnetfd=%d\tis_alive=%d\n", k, client[k].netfd,
           client[k].is_alive);
    /* printf("k=%d\tnetfd=%d\tis_alive=%d\tis_login=%d\n",k,client[k].netfd,client[k].is_alive,client[k].is_login);
     */

    // 从哈希表中移除
    hash_table_remove(&tw->hash_table, curr->client_conn_info.netfd);

    client_info_t *next = curr->next;
    free(curr);
    curr = next;
  }

  tw->wheel[slot_to_check] = NULL; // 清空槽位
}

// 销毁时间轮盘
void destroy_wheel(time_wheel_t *tw) {
  printf("@@destroy_wheel@@\n");
  for (int i = 0; i < QUEUE_SIZE; i++) {
    client_info_t *curr = tw->wheel[i];
    while (curr != NULL) {
      client_info_t *next = curr->next;
      free(curr);
      curr = next;
    }
  }
  hash_table_destroy(&tw->hash_table); // 销毁哈希表
  free(tw);
}

// 输出时间轮盘中的所有内容
void print_time_wheel(time_wheel_t *tw) {
  printf("Time Wheel Content:\n");
  for (int i = 0; i < QUEUE_SIZE; i++) {
    printf("Slot %d:\n", i);
    client_info_t *curr = tw->wheel[i];
    while (curr != NULL) {
      printf("  Client fd: %d, Last Active: %s", curr->client_conn_info.netfd,
             ctime(&curr->lastTime));
      curr = curr->next;
    }
  }
}
